// +build atsamd51

package ws2812

// This file implements the WS2812 protocol for 120MHz Cortex-M4
// microcontrollers.
// Note: This implementation does not work with tinygo 0.9.0 or older.

import (
	"device/arm"
)

// Send a single byte using the WS2812 protocol.
func (d Device) WriteByte(c byte) error {
	// For the Cortex-M4 at 120MHz
	portSet, maskSet := d.Pin.PortMaskSet()
	portClear, maskClear := d.Pin.PortMaskClear()

	// See:
	// https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
	// T0H: 32-34   cycles or  266.67ns -  283.33ns
	// T0L: 101-103 cycles or  841.67ns -  858.33ns
	//   +: 133-137 cycles or 1108.33ns - 1141.67ns
	// T1H: 73-75   cycles or  608.33ns -  625.00ns
	// T1L: 58-60   cycles or  483.33ns -  500.00ns
	//   +: 131-135 cycles or 1091.67ns - 1125.00ns
	// A branch is treated here as 1-3 cycles, because apparently it might get
	// speculated. This is more of a guess than hard fact, because the only docs
	// by ARM that state this are now considered superseded (by what?).
	value := uint32(c) << 24
	arm.AsmFull(`
	1: @ send_bit
		str   {maskSet}, {portSet}     @ [2]   T0H and T0L start here
		lsls  {value}, #1              @ [1]
		nop                            @ [28]
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		bcs.n 2f                       @ [1-3] skip_store
		str   {maskClear}, {portClear} @ [2]   T0H -> T0L transition
	2: @ skip_store
		nop                            @ [41]
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		str   {maskClear}, {portClear} @ [2]   T1H -> T1L transition
		nop                            @ [54]
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		subs  {i}, #1                  @ [1]
		bne.n 1b                       @ [1-3] send_bit
	`, map[string]interface{}{
		"value":     value,
		"i":         8,
		"maskSet":   maskSet,
		"portSet":   portSet,
		"maskClear": maskClear,
		"portClear": portClear,
	})
	return nil
}
